home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / 3D Class Library / 3dcl.cp < prev    next >
Text File  |  1996-06-27  |  29KB  |  1,298 lines

  1. // =======================================================================
  2. //    3D Class Library, © Xilex Group
  3. // - ------------------------------------------------------------------- -
  4. //    Written by Dmitry Boldyrev
  5. // =======================================================================
  6.  
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <math.h>
  10. #include "3dcl.h"
  11.  
  12. WORD matrix[9];
  13. WORD *perspect;
  14. world3d world;
  15. viewPoint camera;
  16.  
  17. struct
  18. {
  19.     WORD    startx;
  20.     WORD    endx;
  21.     WORD     startcol;
  22.     WORD    endcol;
  23.     WORD    x1;
  24.     WORD    y1;
  25.     WORD    x2;
  26.     WORD    y2;
  27. } points[480];
  28.  
  29. extern UBYTE *thepic;        // Holds the 256x256 texture image
  30.  
  31. extern Rect     rBounds;
  32.  
  33. const char Onyx_Banner[] = 
  34. "3D Class Library by Onyx Media Group." \
  35. "All rights reserved.";
  36.  
  37. #define    MIN(a, b)    (((a)<(b))?(a):(b))
  38. #define    MAX(a, b)    (((a)>(b))?(a):(b))
  39.  
  40. // =======================================================================
  41. //    • dotProduct function definition •
  42. // =======================================================================
  43.  
  44. WORD dotProduct(const vector3d *v1, const vector3d *v2)
  45. {
  46.     return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
  47. }
  48.  
  49. static void initPerspect()
  50. {
  51.     perspect = new WORD [32768];
  52.     
  53.     for (WORD count = 0; count < 32768; count++)
  54.         perspect[count] = 1024 * 64 / (count + 1);
  55. }
  56.  
  57. static void delPerspect()
  58. {
  59.     delete[] perspect;
  60. }
  61.  
  62. // =======================================================================
  63. //    • vertex class definitions •
  64. // =======================================================================
  65.  
  66. vertex::vertex()
  67. {
  68. }
  69.  
  70. static inline void subVectors(const vector3d *a, const vector3d *b, vector3d *c)
  71. {
  72.     c->x = a->x - b->x;
  73.     c->y = a->y - b->y;
  74.     c->z = a->z - b->z;
  75. }
  76.  
  77. // =======================================================================
  78. //    project the point to the screen
  79. // =======================================================================
  80.  
  81. void vertex::xform2d()
  82. {
  83.     static vector3d vec;
  84.     
  85.     subVectors(&xyz, &camera.view, &vec);
  86.  
  87.     if (vec.z)
  88.     {
  89.         xy.x = ((vec.x<<10)/vec.z) + middle.h;
  90.         xy.y =  middle.v - ((vec.y<<10)/vec.z);  
  91.     } else 
  92.     {
  93.         xy.x = vec.x;
  94.         xy.y = vec.y;
  95.     } 
  96. }
  97.  
  98. // =======================================================================
  99. //    zero the normal for this point (used for gouraud shading)
  100. // =======================================================================
  101.  
  102. void vertex::zeroNormal()
  103. {
  104.     normal.x = 0;
  105.     normal.y = 0;
  106.     normal.z = 0;
  107.  
  108.     nCount = 0;
  109. }
  110.  
  111. void vertex::setTo(WORD x, WORD y, WORD z, WORD inKind)
  112. {
  113.     xyz.x = x;
  114.     xyz.y = y;
  115.     xyz.z = z;
  116.   
  117.     mKind = inKind;
  118.  
  119.     zeroNormal();
  120.     xform2d();
  121. }
  122.  
  123. vertex::vertex(WORD x, WORD y, WORD z, WORD inKind)
  124. {
  125.     setTo(x, y, z, inKind);
  126. }
  127.  
  128. // =======================================================================
  129. //    translate (move) a point by (dX, dY, dZ)
  130. // =======================================================================
  131.  
  132. void vertex::translate(WORD dX, WORD dY, WORD dZ)
  133. {
  134. }
  135.  
  136. // =======================================================================
  137. //    add (dX, dY, dZ) to the normal for this point
  138. // =======================================================================
  139.  
  140. void vertex::addNormal(WORD dX, WORD dY, WORD dZ)
  141. {
  142.     normal.x += dX;
  143.     normal.y += dY;
  144.     normal.z += dZ;
  145.  
  146.     nCount ++;
  147. }
  148.  
  149. // =======================================================================
  150. //    average the normal of this point
  151. // =======================================================================
  152.  
  153. void vertex::avgNormal()
  154. {
  155.     if (nCount)
  156.     {
  157.         normal.x /= nCount;
  158.         normal.y /= nCount;
  159.         normal.z /= nCount;
  160.         
  161.         WORD d = SQRT(SQR(normal.x) + SQR(normal.y) + SQR(normal.z));
  162.         
  163.         normal.x = (normal.x << 16) / d;
  164.         normal.y = (normal.y << 16) / d;
  165.         normal.z = (normal.z << 16) / d;
  166.     }
  167. }
  168. // =======================================================================
  169. //    rotate a point about its origin (faster method, *mat array
  170. //    used to store sin/cos data that remains constant for all
  171. //    points in a given object
  172. // =======================================================================
  173.  
  174. void vertex::localRotate(matrix3d mat)
  175. {
  176.     static vector3d local;
  177.  
  178.     local.x = (mat[0][0] * xyz.x + mat[0][1] * xyz.y + mat[0][2] * xyz.z) >> 16;
  179.     local.y = (mat[1][0] * xyz.x + mat[1][1] * xyz.y + mat[1][2] * xyz.z) >> 16;
  180.     local.z = (mat[2][0] * xyz.x + mat[2][1] * xyz.y + mat[2][2] * xyz.z) >> 16;
  181.  
  182.     xyz = local;
  183.     
  184.     xform2d();
  185. }
  186.  
  187. vertex::~vertex()
  188. {
  189. }
  190.  
  191. // =======================================================================
  192. //    • polygon class definitions •
  193. // =======================================================================
  194.  
  195. polygon::polygon()
  196. {
  197. }
  198.  
  199. polygon::polygon(vertex *v1, vertex *v2, vertex *v3)
  200. {
  201.     setTo(v1, v2, v3);
  202. }
  203.  
  204. void polygon::setTo(vertex *v1, vertex *v2, vertex *v3)
  205. {
  206.     register double i, j, k, d;
  207.     
  208.     p1 = v1;
  209.     p2 = v2;
  210.     p3 = v3;
  211.  
  212.     //    Calculating the normal to the polygon
  213.     i = (((p2->xyz.y - p1->xyz.y) * (p3->xyz.z - p1->xyz.z)) -
  214.          ((p2->xyz.z - p1->xyz.z) * (p3->xyz.y - p1->xyz.y)));
  215.  
  216.     j = (((p2->xyz.z - p1->xyz.z) * (p3->xyz.x - p1->xyz.x)) -
  217.          ((p2->xyz.x - p1->xyz.x) * (p3->xyz.z - p1->xyz.z)));
  218.  
  219.     k = (((p2->xyz.x - p1->xyz.x) * (p3->xyz.y - p1->xyz.y)) -
  220.          ((p2->xyz.y - p1->xyz.y) * (p3->xyz.x - p1->xyz.x)));
  221.  
  222.     d = SQRT(SQR(i) + SQR(j) + SQR(k));
  223.  
  224.     i = (i / d * 32768);
  225.     j = (j / d * 32768);
  226.     k = (k / d * 32768);
  227.  
  228.     normal.setTo(i, j, k, isNormal);
  229. }
  230.  
  231. // =======================================================================
  232. //    average Z value of a polygon, used for depth sorting
  233. // =======================================================================
  234.  
  235. WORD polygon::calcAvgZ()
  236. {
  237.     return (averageZ = 32767 + ((p1->xyz.z + p2->xyz.z + p3->xyz.z) / 3));
  238. }
  239.  
  240. void polygon::setNewOrigin(vertex *p)
  241. {
  242.     p1->setNewOrigin(p);
  243.     p2->setNewOrigin(p);
  244.     p3->setNewOrigin(p);
  245.     
  246.     normal.setNewOrigin(p);
  247. }
  248.  
  249. // =======================================================================
  250. //    this function should be called for all polygons in an object,
  251. //    following which point->avgNormals() should be called for all
  252. //    points in an object.  The object3d->setGNormals function takes
  253. //    care of all of this...
  254. // =======================================================================
  255.  
  256. void polygon::setGNormals()
  257. {
  258.        p1->addNormal(normal.xyz.x, normal.xyz.y, normal.xyz.z);
  259.     p2->addNormal(normal.xyz.x, normal.xyz.y, normal.xyz.z);
  260.     p3->addNormal(normal.xyz.x, normal.xyz.y, normal.xyz.z);
  261. }
  262.  
  263.  
  264. void polygon::renderFlat()
  265. {
  266. }
  267.  
  268. void polygon::renderGouraudTexMap()
  269. {
  270. }
  271.  
  272. void polygon::renderWire()
  273. {
  274.     ::ForeColor(whiteColor);
  275.         
  276.     ::MoveTo(p1->xy.x, p1->xy.y);
  277.     ::LineTo(p2->xy.x, p2->xy.y);
  278.     ::LineTo(p3->xy.x, p3->xy.y);
  279.     ::LineTo(p1->xy.x, p1->xy.y);
  280.     
  281.     /*::ForeColor(greenColor);
  282.     ::MoveTo(p1->xy.x, p1->xy.y);
  283.     ::LineTo(normal.xy.x, normal.xy.y); */
  284. }
  285.  
  286. void polygon::renderNone()
  287. {
  288. }
  289.  
  290. #if GENERATINGCFM
  291. asm void limit_upoint(register upoint *p, register Rect *r);
  292. #pragma parameter limit_upoint(__r3, __r4)
  293. asm void limit_upoint(
  294.     register upoint *p, 
  295.     register Rect    *r)
  296. {
  297.     lwz        r5, p->x            //    r5 = p->x
  298.     lha        r6, r->left            //    r6 = r->left
  299.     cmpw    r5, r6                //    p->x < r->left ?
  300.     bge        @1                    //    NO
  301.     mr        r5, r6                //    r5 = r6
  302.     stw        r6, p->x            //    YES
  303. @1    lha        r6, r->right        //    r6 =  r->right
  304.     cmpw    r5, r6                //    p->x > r->right ?
  305.     ble        @2                    //    NO
  306.     mr        r5, r6                //    r5 = r6
  307.     stw        r6, p->x            //     YES
  308. @2    lwz        r5, p->y            //    r5 = p->y
  309.     lha        r6, r->top            //    r6 =  r->top
  310.     cmpw    r5, r6                //    p->y < r->top ?
  311.     bge        @3                    //    NO
  312.     mr        r5, r6                //    r5 = r6
  313.     stw        r6, p->y            //    YES
  314. @3    lha        r6, r->bottom        //    r6 =  r->bottom
  315.     cmpw    r5, r6                //    p->y > r->bottom ?
  316.     ble        @4                    //    NO
  317.     mr        r5, r6                //    r5 = r6
  318.     stw        r6, p->y            //    YES
  319. @4    blr
  320. }
  321. #else
  322. static void limit_upoint(
  323.     register upoint *p, 
  324.     register Rect    *r)
  325. {
  326.     if (p->x < r->left) {
  327.         p->x = r->left;
  328.     } else
  329.     if (p->x > r->right) {
  330.         p->x = r->right;
  331.     }
  332.     
  333.     if (p->y < r->top) {
  334.         p->y = r->top;
  335.     } else
  336.     if (p->y > r->bottom) {
  337.         p->y = r->bottom;
  338.     } 
  339. }
  340. #endif
  341.  
  342. void polygon::renderTexMap()
  343. {
  344.     register WORD     x, mx, xcoord, ycoord, xstep, ystep, y;
  345.     register upoint pTop, pMid, pBot;
  346.     register UBYTE  *src, *dest;
  347.     
  348.     if (p2->xy.y > p1->xy.y)
  349.     {
  350.         pTop = p1->xy; pBot = p2->xy;
  351.     } else
  352.     {
  353.         pTop = p2->xy; pBot = p1->xy;
  354.     }
  355.     if (pTop.y > p3->xy.y)
  356.     {
  357.         pTop = p3->xy;
  358.         if (p2->xy.y > p1->xy.y)
  359.         {
  360.             pMid = p1->xy; pBot = p2->xy;
  361.         } else
  362.         {
  363.             pMid = p2->xy; pBot = p1->xy;
  364.         }
  365.     } else
  366.     {
  367.         if (pBot.y > p3->xy.y)
  368.         {
  369.             pMid = p3->xy;
  370.         } else
  371.         {
  372.             pMid = pBot; pBot = p3->xy;
  373.         }
  374.     }
  375.     
  376.     limit_upoint(&pTop, &rBounds);
  377.     limit_upoint(&pMid, &rBounds);
  378.     limit_upoint(&pBot, &rBounds);
  379.  
  380.     //    p3.x, p3.y, p3.c -> p1.x, p1.y, p1.c
  381.     
  382. #if !GENERATINGCFM
  383.     if (pBot.y - pTop.y)
  384.     {
  385. #endif
  386.     x  = pTop.x << 8;
  387.     mx = ((pBot.x - pTop.x) << 8) / (pBot.y - pTop.y);
  388.     
  389.     xcoord = pTop.u << 8;
  390.     xstep  = ((pBot.u - pTop.u) << 8) / (pBot.y - pTop.y);
  391.  
  392.     ycoord = pTop.v << 8;
  393.     ystep  = ((pBot.v - pTop.v) << 8) / (pBot.y - pTop.y);
  394.     
  395.     for (y = pTop.y; y < pBot.y; y++) 
  396.     {
  397.         points[y].startx = x >> 8;
  398.         points[y].x1 = xcoord >> 8;
  399.         points[y].y1 = ycoord >> 8;
  400.         points[y].endx = 0;
  401.         points[y].x2 = 0;
  402.         points[y].y2 = 0;
  403.  
  404.         x += mx;
  405.         xcoord += xstep;
  406.         ycoord += ystep;
  407.     }
  408. #if !GENERATINGCFM
  409.     }
  410. #endif        
  411.  
  412.     //    X1, p1.y, p1.c -> p2.x, p2.y, p2.c
  413. #if !GENERATINGCFM
  414.     if (pMid.y - pTop.y)
  415.     {
  416. #endif
  417.     x  = pTop.x << 8;
  418.     mx = ((pMid.x - pTop.x) << 8) / (pMid.y - pTop.y);
  419.     
  420.     xcoord = pTop.u << 8;
  421.     xstep  = ((pMid.u - pTop.u) << 8) / (pMid.y - pTop.y);
  422.  
  423.     ycoord = pTop.v << 8;
  424.     ystep  = ((pMid.v - pTop.v) << 8) / (pMid.y - pTop.y);
  425.     
  426.     for (y = pTop.y; y < pMid.y; y++) 
  427.     {
  428.         if (points[y].startx)
  429.         {
  430.             points[y].endx = x >> 8;
  431.             points[y].x2 = xcoord >> 8;
  432.             points[y].y2 = ycoord >> 8;
  433.         } else
  434.         {
  435.             points[y].startx = x >> 8;
  436.             points[y].x1 = xcoord >> 8;
  437.             points[y].y1 = ycoord >> 8;
  438.         }
  439.         x += mx;
  440.         xcoord += xstep;
  441.         ycoord += ystep;
  442.     }
  443. #if !GENERATINGCFM
  444.     }
  445. #endif
  446.     //    p2.x, p2.y, p2.c -> p3.x, p3.y, p3.c
  447.     
  448. #if !GENERATINGCFM
  449.     if (pBot.y - pMid.y)
  450.     {
  451. #endif
  452.     x  = pMid.x << 8;
  453.     mx = ((pBot.x - pMid.x) << 8) / (pBot.y - pMid.y);
  454.     
  455.     xcoord = pMid.u << 8;
  456.     xstep  = ((pBot.u - pMid.u) << 8) / (pBot.y - pMid.y);
  457.  
  458.     ycoord = pMid.v << 8;
  459.     ystep  = ((pBot.v - pMid.v) << 8) / (pBot.y - pMid.y);
  460.     
  461.     for (y = pMid.y; y < pBot.y; y++) 
  462.     {
  463.         if (points[y].startx)
  464.         {
  465.             points[y].endx = x >> 8;
  466.             points[y].x2 = xcoord >> 8;
  467.             points[y].y2 = ycoord >> 8;
  468.         } else
  469.         {
  470.             points[y].startx = x >> 8;
  471.             points[y].x1 = xcoord >> 8;
  472.             points[y].y1 = ycoord >> 8;
  473.         }
  474.         x += mx;
  475.         xcoord += xstep;
  476.         ycoord += ystep;
  477.     }
  478. #if !GENERATINGCFM
  479.     }
  480. #endif
  481.     //    Do the drawing
  482.  
  483.     for (y = pTop.y; y < pBot.y; y++)
  484.     {
  485.         mx = points[y].endx - points[y].startx;
  486.         if (mx)
  487.         {
  488.             if (mx < 0)
  489.             {
  490.                 x = points[y].startx; points[y].startx = points[y].endx; points[y].endx = x;
  491.                 x = points[y].x1; points[y].x1 = points[y].x2; points[y].x2 = x;
  492.                 x = points[y].y1; points[y].y1 = points[y].y2; points[y].y2 = x;            
  493.                 mx = -mx;
  494.             }
  495.             
  496.             xcoord = points[y].x1 << 8;
  497.             xstep = ((points[y].x2 - points[y].x1) << 8) / mx;
  498.     
  499.             ycoord = points[y].y1 << 8;
  500.             ystep = ((points[y].y2 - points[y].y1) << 8) / mx;
  501.             
  502.             dest = (UBYTE*)baseAddr + y * rowBytes + points[y].startx;
  503.             for (x = mx; x >= 0; x--)
  504.             {
  505.                 *dest++ = thepic[(ycoord & 0xFFFFFF00) + (xcoord>>8)];
  506.                 xcoord += xstep;
  507.                 ycoord += ystep;
  508.             }
  509.         }
  510.     }
  511. }
  512.  
  513. void polygon::renderGouraud()
  514. {
  515.      register WORD x, mx, c, mc, y;
  516.     register upoint pTop, pMid, pBot;
  517.     register Ptr  base;
  518.  
  519.     /* if ((dotProduct(&p1->normal, &camera.view) <= 0) &&
  520.          (dotProduct(&p2->normal, &camera.view) <= 0) &&
  521.          (dotProduct(&p3->normal, &camera.view) <= 0))
  522.         return; 
  523.     */
  524.  
  525.     p1->xy.c = ABS(dotProduct(&p1->normal, &camera.light)) >> 26;
  526.     p2->xy.c = ABS(dotProduct(&p2->normal, &camera.light)) >> 26;
  527.     p3->xy.c = ABS(dotProduct(&p3->normal, &camera.light)) >> 26;
  528.     
  529.     if (p2->xy.y > p1->xy.y)
  530.     {
  531.         pTop = p1->xy; pBot = p2->xy;
  532.     } else
  533.     {
  534.         pTop = p2->xy; pBot = p1->xy;
  535.     }
  536.     if (pTop.y > p3->xy.y)
  537.     {
  538.         pTop = p3->xy;
  539.         if (p2->xy.y > p1->xy.y)
  540.         {
  541.             pMid = p1->xy; pBot = p2->xy;
  542.         } else
  543.         {
  544.             pMid = p2->xy; pBot = p1->xy;
  545.         }
  546.     } else
  547.     {
  548.         if (pBot.y > p3->xy.y)
  549.         {
  550.             pMid = p3->xy;
  551.         } else
  552.         {
  553.             pMid = pBot; pBot = p3->xy;
  554.         }
  555.     }
  556.     
  557.     limit_upoint(&pTop, &rBounds);
  558.     limit_upoint(&pMid, &rBounds);
  559.     limit_upoint(&pBot, &rBounds);
  560.  
  561.     //    p3.x, p3.y, p3.c -> p1.x, p1.y, p1.c
  562.     
  563. #if !GENERATINGCFM
  564.     if (pBot.y - pTop.y)
  565.     {
  566. #endif
  567.         x = pTop.x << 16;
  568.         mx = ((pBot.x - pTop.x) << 16) / (pBot.y - pTop.y);
  569.         
  570.         c = pTop.c << 16;
  571.         mc = ((pBot.c - pTop.c) << 16) / (pBot.y - pTop.y);
  572.         
  573.         for (y = pTop.y; y < pBot.y; y++) 
  574.         {
  575.             points[y].startx = x >> 16;
  576.             points[y].startcol = c >> 16;
  577.             points[y].endx = points[y].endcol = 0;
  578.  
  579.             x += mx;
  580.             c += mc;
  581.         }
  582. #if !GENERATINGCFM
  583.     }    
  584. #endif
  585.  
  586.     //    X1, p1.y, p1.c -> p2.x, p2.y, p2.c
  587. #if !GENERATINGCFM
  588.     if (pMid.y - pTop.y)
  589.     {
  590. #endif
  591.         x = pTop.x << 16;
  592.         mx = ((pMid.x - pTop.x) << 16) / (pMid.y - pTop.y);
  593.         
  594.         c = pTop.c << 16;
  595.         mc = ((pMid.c - pTop.c) << 16) / (pMid.y - pTop.y);
  596.         
  597.         for (y = pTop.y; y < pMid.y; y++) 
  598.         {
  599.                 if (points[y].startx)
  600.                 {
  601.                     points[y].endx = x >> 16;
  602.                     points[y].endcol = c >> 16;
  603.                 } else
  604.                 {
  605.                     points[y].startx = x >> 16;
  606.                     points[y].startcol = c >> 16;
  607.                 }
  608.             x += mx;
  609.             c += mc;
  610.         }
  611. #if !GENERATINGCFM
  612.     }
  613. #endif
  614.     //    p2.x, p2.y, p2.c -> p3.x, p3.y, p3.c
  615.     
  616. #if !GENERATINGCFM
  617.     if (pBot.y - pMid.y)
  618.     {
  619. #endif
  620.         x = pMid.x << 16;
  621.         mx = ((pBot.x - pMid.x) << 16) / (pBot.y - pMid.y);
  622.         
  623.         c = pMid.c << 16;
  624.         mc = ((pBot.c - pMid.c) << 16) / (pBot.y - pMid.y);
  625.         
  626.         for (y = pMid.y; y < pBot.y; y++) 
  627.         {
  628.             //if ((y >= 0) & (y < 480))
  629.                 if (points[y].startx)
  630.                 {
  631.                     points[y].endx = x >> 16;
  632.                     points[y].endcol = c >> 16;
  633.                 } else
  634.                 {
  635.                     points[y].startx = x >> 16;
  636.                     points[y].startcol = c >> 16;
  637.                 }
  638.             x += mx;
  639.             c += mc;
  640.         }
  641. #if !GENERATINGCFM
  642.     }    
  643. #endif
  644.     //    Do the drawing
  645.     register WORD start_x, end_x, start_col, end_col;
  646.     
  647.     base = baseAddr + pTop.y * rowBytes;
  648.     for (y = pTop.y; y < pBot.y; y++)
  649.     {
  650.         start_x = points[y].startx; //xTop
  651.         end_x = points[y].endx;     //xBot
  652. #if !GENERATINGCFM
  653.         if (end_x - start_x)
  654.         {    
  655. #endif
  656.             start_col = points[y].startcol;
  657.             end_col = points[y].endcol;
  658.             
  659.             if (end_x < start_x) 
  660.             {
  661.                 start_x = end_x; end_x = points[y].startx;
  662.                 start_col = end_col; end_col = points[y].startcol;
  663.             }
  664.             c = start_col << 16;
  665.             mc = ((end_col - start_col) << 16) / (end_x - start_x);
  666.             
  667.             for (x = start_x; x < end_x; x++)
  668.             {
  669.                 *(base+x) = c >> 16;
  670.                 c += mc;
  671.             }
  672.             base += rowBytes;
  673. #if !GENERATINGCFM
  674.         }
  675. #endif        
  676.     }
  677.     
  678. }
  679.  
  680. void polygon::calcThetaPhi(vector3d v, WORD &r_theta, WORD &r_phi)
  681. {
  682.     register double x, y, z, r, rho, theta, phi;
  683.     
  684.     x = normal.xyz.x / 65536.0;
  685.     y = normal.xyz.y / 65536.0;
  686.     z = normal.xyz.z / 65536.0;
  687.     
  688.     r = SQRT(SQR(x) + SQR(y));
  689.     rho = SQRT(SQR(r) + SQR(z));
  690.     
  691.         phi = acos(z / r);
  692.         theta = asin(y / r);
  693.  
  694.     r_theta = (theta / PI) * 65536.0; 
  695.     r_phi = (phi / PI) * 65536.0; 
  696. }
  697.  
  698. #define WRAP(x)    ABS(x % 256)
  699. void polygon::applyTexture(WORD width, WORD height, WORD depth)
  700. {
  701.     p1->xy.u = WRAP((p1->xyz.x<<8)/width); 
  702.     p1->xy.v = WRAP((p1->xyz.y<<8)/height);
  703.  
  704.     p2->xy.u = WRAP((p2->xyz.x<<8)/width); 
  705.     p2->xy.v = WRAP((p2->xyz.y<<8)/height);
  706.  
  707.     p3->xy.u = WRAP((p3->xyz.x<<8)/width); 
  708.     p3->xy.v = WRAP((p3->xyz.y<<8)/height); 
  709.     
  710. }
  711.  
  712. // ====================================================================
  713. //    must be called to initialize rendering proc
  714. // ====================================================================
  715.  
  716. void polygon::renderPoly(BYTE method)
  717. {
  718.     switch (method)
  719.     {
  720.         case sGouraudTexMap:
  721.             renderGouraudTexMap();
  722.             break;
  723.         case sTexMap:
  724.             renderTexMap();
  725.             break;
  726.         case sGouraud:
  727.             renderGouraud();
  728.             break;
  729.         case sFlat:
  730.             renderFlat();
  731.             break;
  732.         case sWire:
  733.             renderWire();
  734.             break;
  735.         default:
  736.             break;
  737.     }
  738. }
  739.  
  740. polygon::~polygon()
  741. {
  742. }
  743.  
  744.  
  745. // ====================================================================
  746. //    • object3d class definitions •
  747. // ====================================================================
  748.  
  749. object3d::object3d()
  750. {
  751.     xDeg = 0;
  752.     yDeg = 0;
  753.     zDeg = 0;
  754. }
  755.  
  756. WORD object3d::getPointNum(vertex *p)
  757. {
  758.       register vertex *pt3d;
  759.     
  760.     count = 0;
  761.     points.GoToFirstNode();
  762.     while (pt3d = (vertex*) points.GetNextNode())
  763.     {
  764.         if (pt3d == p)
  765.             return count;
  766.         count++;
  767.     }
  768.     return -1;
  769. }
  770.  
  771. vertex *object3d::getPointAddr(WORD pNum)
  772. {
  773.     register WORD    count;
  774.       register vertex *pt3d;
  775.     
  776.     count = 0;
  777.     points.GoToFirstNode();
  778.     while (pt3d = (vertex*) points.GetNextNode())
  779.     {
  780.         if (count == pNum)
  781.             return pt3d;
  782.         count ++;
  783.     }
  784.     return 0;
  785. }
  786.  
  787. // =======================================================================
  788. //    binary format save routine
  789. // =======================================================================
  790.  
  791. void object3d::save(char *fname)
  792. {
  793.     FILE *fp = ::fopen(fname, "wb");
  794.     
  795.     objFileHeader header;
  796.  
  797.     // assumes fp has already been opened, so we can store multiple objects
  798.     // in the same file
  799.  
  800.     header.numPoints = points.NumNodes();
  801.     header.numPolys = polys.NumNodes();
  802.  
  803.     fwrite(&header, sizeof(objFileHeader), 1, fp);
  804.  
  805.      vertex *pt3d;    
  806.     points.GoToFirstNode();
  807.     while (pt3d = (vertex*) points.GetNextNode())
  808.     {
  809.         fwrite(&pt3d->xyz, sizeof(vector3d), 1, fp);
  810.     }
  811.  
  812.     polygon* poly;
  813.     polyRec  pRec;
  814.  
  815.     polys.GoToFirstNode();
  816.     while (poly = (polygon*) polys.GetNextNode())
  817.     {
  818.         pRec.p1 = getPointNum(poly->p1);
  819.         pRec.p2 = getPointNum(poly->p2);
  820.         pRec.p3 = getPointNum(poly->p3);
  821.         pRec.color = 0xFF;
  822.           fwrite(&pRec, sizeof(polyRec), 1, fp);
  823.     }
  824.     fclose(fp);
  825. }
  826.  
  827. void object3d::addLocalPoint(vertex *p)
  828. {
  829.    // p->globalXform2origin(origin);
  830.     points.AppendNode(p);
  831. }
  832.  
  833. // =======================================================================
  834. //    add a point whose coordinates are given as local to the origin of
  835. //    this object to this objects list of points
  836. // =======================================================================
  837.  
  838. void object3d::addLocalPoint(WORD x, WORD y, WORD z, WORD inKind)
  839. {
  840.     addLocalPoint(new vertex(x, y, z, inKind));
  841. }
  842.  
  843. // ====================================================================
  844. //    add a local polygon (whose vertices are local points)
  845. // ====================================================================
  846.  
  847. void object3d::addLocalPoly(polygon *pg)
  848. {
  849.     polys.AppendNode(pg);
  850.     addLocalPoint(&pg->normal);
  851. }
  852.  
  853. void object3d::addLocalPoly(WORD p1, WORD p2, WORD p3)
  854. {
  855.     addLocalPoly(new polygon(getPointAddr(p1), getPointAddr(p2), getPointAddr(p3)));
  856. }
  857.  
  858. // =======================================================================
  859. //    binary format load routine
  860. // =======================================================================
  861.  
  862. void object3d::load(char *fname)
  863. {
  864.     WORD    numPoints, numPolys;
  865.     FILE     *fp = ::fopen(fname, "rb");
  866.     
  867.     objFileHeader header;
  868.  
  869.     // free old data
  870.  
  871.     points.FreeNodes();
  872.     polys.FreeNodes();
  873.  
  874.     // assumes fp has already been opened, so we can store multiple objects
  875.     // in the same file
  876.  
  877.     fread(&header, sizeof(objFileHeader), 1, fp);
  878.  
  879.     numPoints = header.numPoints;
  880.     numPolys  = header.numPolys;
  881.  
  882.     vector3d ptRec;
  883.        for (count = 0; count < numPoints; count++)
  884.     {
  885.         fread(&ptRec, sizeof(vector3d), 1, fp);
  886.         addLocalPoint(ptRec.x, ptRec.y, ptRec.z, isVertex);
  887.     }
  888.     
  889.     polyRec pRec;
  890.     for (count = 0; count < numPolys; count++)
  891.     {
  892.           fread(&pRec, sizeof(polyRec), 1, fp);
  893.         addLocalPoly(pRec.p1, pRec.p2, pRec.p3);
  894.     }
  895.     fclose(fp);
  896. }
  897.  
  898. void object3d::importASC(char *fname)
  899. {
  900.     register FILE    *inFile;
  901.     register WORD     tempInt, vertices, faces,             // Considering only 2i model
  902.                     count, tempA, tempB, tempC;
  903.     register char     tempChar;
  904.     register float     tempX, tempY, tempZ;
  905.     register char     tempStr[255];
  906.  
  907.     inFile = fopen(fname, "rt");
  908.     if (inFile == NULL)
  909.         return;
  910.     
  911.     while (strncmp(tempStr, "Vertices", 8))
  912.     {
  913.         fscanf(inFile, "%s", tempStr);
  914.         if (feof(inFile))
  915.             return;
  916.     }
  917.  
  918.     tempChar = fgetc(inFile);
  919.     fscanf(inFile, "%d", &vertices);
  920.     while (strncmp(tempStr, "Faces", 5))
  921.     {
  922.         fscanf(inFile, "%s", tempStr);
  923.         if (feof(inFile))
  924.             return;
  925.     }
  926.  
  927.     tempChar = fgetc(inFile);
  928.     fscanf(inFile, "%d", &faces);
  929.  
  930.     while (strncmp(tempStr, "Vertex", 6))
  931.     {
  932.         fscanf(inFile, "%s", tempStr);
  933.         if (feof(inFile))
  934.             return;
  935.     }
  936.     while (strncmp(tempStr, "list:", 5))
  937.     {
  938.         fscanf(inFile, "%s", tempStr);
  939.         if (feof(inFile))
  940.             return;
  941.     }
  942.  
  943.     for (count = 0; count < vertices; count++)
  944.     {
  945.         while (strncmp(tempStr, "Vertex", 6))
  946.         {
  947.             fscanf(inFile, "%s", tempStr);
  948.             if (feof(inFile))
  949.                 return;
  950.         }
  951.  
  952.         fscanf(inFile, "%d", &tempInt);
  953.         fscanf(inFile, "%s", tempStr);
  954.         fscanf(inFile, "%s", tempStr);
  955.         fscanf(inFile, "%f", &tempX);
  956.         fscanf(inFile, "%s", tempStr);
  957.         fscanf(inFile, "%f", &tempY);
  958.         fscanf(inFile, "%s", tempStr);
  959.         fscanf(inFile, "%f", &tempZ);
  960.  
  961.         addLocalPoint(tempX, tempY, tempZ, isVertex);
  962.     }
  963.  
  964.     while (strncmp(tempStr, "Face", 4))
  965.     {
  966.         fscanf(inFile, "%s", tempStr);
  967.         if (feof(inFile))
  968.             return;
  969.     }
  970.  
  971.     while (strncmp(tempStr, "list", 4))
  972.     {
  973.         fscanf(inFile, "%s", tempStr);
  974.         if (feof(inFile))
  975.             return;
  976.     }
  977.  
  978.     for (count = 0; count < faces; count++)
  979.     {
  980.         while (strncmp(tempStr, "Face", 4))
  981.         {
  982.             fscanf(inFile, "%s", tempStr);
  983.             if (feof(inFile))
  984.                 return;
  985.         }
  986.  
  987.         fscanf(inFile, "%d", &tempInt);
  988.         fscanf(inFile, "%s", tempStr);
  989.  
  990.         while (fgetc(inFile) != 'A');
  991.             fgetc(inFile);              // get the ':' character
  992.         fscanf(inFile, "%d", &tempA);   // get value for vertex A
  993.  
  994.         while (fgetc(inFile) != 'B');
  995.         fgetc(inFile);
  996.         fscanf(inFile, "%d", &tempB);
  997.  
  998.         while (fgetc(inFile) != 'C');
  999.         fgetc(inFile);
  1000.         fscanf(inFile, "%d", &tempC);
  1001.  
  1002.         addLocalPoly(tempA, tempB, tempC);
  1003.     }
  1004.     fclose(inFile);
  1005. }
  1006.  
  1007. #define koeff 100
  1008. void object3d::importV3D(char *fname)
  1009. {
  1010.     register FILE     *inFile;
  1011.     register WORD     vertices, faces, count, tempA, 
  1012.                     tempB, tempC, tempD, color;
  1013.     register SINGLE tempX, tempY, tempZ;
  1014.     register char    tempStr[255];
  1015.     
  1016.        inFile = fopen(fname, "rt");
  1017.     if (inFile == NULL)
  1018.        return;
  1019.  
  1020.     fscanf(inFile, "%s", tempStr);
  1021.     if (strncmp(tempStr, "3DG1", 4) != 0)
  1022.         return;
  1023.     fscanf(inFile, "%d", &vertices);
  1024.   
  1025.     for (count = 0; count < vertices; count++)
  1026.     {
  1027.         fscanf(inFile, "%f %f %f", &tempX, &tempY, &tempZ);
  1028.         addLocalPoint(tempX*koeff, tempY*koeff, tempZ*koeff, isVertex);
  1029.     }
  1030.  
  1031.     for (count = 0; ; count++)
  1032.     {
  1033.         fscanf(inFile, "%d", &faces);
  1034.         switch (faces)
  1035.         {
  1036.             case 1:
  1037.                 fscanf(inFile, "%d %d", &tempA, &color);
  1038.                  addLocalPoly(tempA, tempA, tempA);
  1039.                 break;
  1040.                case 2:
  1041.                 fscanf(inFile, "%d %d %d", &tempA, &tempB, &color);
  1042.                  addLocalPoly(tempA, tempB, tempA);
  1043.                 break;
  1044.             case 3:
  1045.                 fscanf(inFile, "%d %d %d %d", &tempA, &tempB, &tempC, &color);
  1046.                  addLocalPoly(tempA, tempB, tempC);
  1047.                 break;
  1048.             case 4:    
  1049.                 fscanf(inFile, "%d %d %d %d %d", &tempA, &tempB, &tempC, &tempD, &color);
  1050.                 addLocalPoly(tempA, tempB, tempC);
  1051.                 addLocalPoly(tempC, tempD, tempA);
  1052.                 break;
  1053.             default:
  1054.                 fgets(tempStr, 255, inFile);
  1055.                 break;
  1056.         }
  1057.         if (feof(inFile)) 
  1058.                break;
  1059.     }
  1060.     fclose(inFile);
  1061. }
  1062.  
  1063. // =======================================================================
  1064. //    rotate this object about it's origin
  1065. // =======================================================================
  1066.  
  1067. void object3d::localRotate()
  1068. {
  1069.      register vertex *pt3d;
  1070.     
  1071.     points.GoToFirstNode();
  1072.     while (pt3d = (vertex*) points.GetNextNode())
  1073.         pt3d->localRotate(mat);
  1074. }
  1075.  
  1076. void object3d::applyTexture()
  1077. {
  1078.      polygon *poly;
  1079.     WORD    width, height, depth;
  1080.     
  1081.     calcBounds(width, height, depth);
  1082.  
  1083.     polys.GoToFirstNode();
  1084.     while (poly = (polygon*) polys.GetNextNode())
  1085.         poly->applyTexture(width, height, depth);
  1086. }
  1087.  
  1088. void object3d::calcBounds(WORD &width, WORD &height, WORD &depth)
  1089. {
  1090.      register vertex *pt3d;
  1091.     register WORD    minX, minY, minZ,
  1092.                     maxX, maxY, maxZ;
  1093.     
  1094.     minX = minY = minZ = 32767;
  1095.     maxX = maxY = maxZ = -32767;
  1096.     
  1097.     points.GoToFirstNode();
  1098.     while (pt3d = (vertex*) points.GetNextNode())
  1099.     {
  1100.         if (pt3d->mKind == isVertex)
  1101.         {
  1102.             minX = MIN(minX, pt3d->xyz.x); 
  1103.             minY = MIN(minY, pt3d->xyz.y); 
  1104.             minZ = MIN(minZ, pt3d->xyz.z);
  1105.             
  1106.             maxX = MAX(maxX, pt3d->xyz.x);
  1107.             maxY = MAX(maxY, pt3d->xyz.y);
  1108.             maxZ = MAX(maxZ, pt3d->xyz.z);
  1109.         }
  1110.     }
  1111.     width = maxX - minX; height = maxY - minY; depth = maxZ - minZ;
  1112. }
  1113.  
  1114. #define    TORAD(x)    ((x) * PI / 180.0)
  1115.  
  1116. void object3d::makeRotMatrix(WORD Xrot, WORD Yrot, WORD Zrot)
  1117. {
  1118.     register double    cXrot, cYrot, cZrot,
  1119.                       sXrot, sYrot, sZrot;
  1120.  
  1121.     cXrot = cos(TORAD(Xrot)); cYrot = cos(TORAD(Yrot)); cZrot = cos(TORAD(Zrot));
  1122.     sXrot = sin(TORAD(Xrot)); sYrot = sin(TORAD(Yrot)); sZrot = sin(TORAD(Zrot));
  1123.     
  1124.     mat[0][0] = 65536 * (cYrot * cZrot);
  1125.     mat[0][1] = 65536 * (cZrot * sXrot * sYrot - sZrot * cXrot);
  1126.     mat[0][2] = 65536 * (-(cXrot * cZrot * sYrot + sXrot * sZrot));
  1127.     mat[1][0] = 65536 * (sZrot * cYrot);
  1128.     mat[1][1] = 65536 * (sXrot * sYrot * sZrot + cXrot * cZrot);
  1129.     mat[1][2] = 65536 * (-(sYrot * sZrot * cXrot) + sXrot * cZrot);
  1130.     mat[2][0] = 65536 * (sYrot);
  1131.     mat[2][1] = 65536 * (-sXrot * cYrot);
  1132.     mat[2][2] = 65536 * (cXrot * cYrot);
  1133. }
  1134.  
  1135. // =======================================================================
  1136. //    translate (move) this object
  1137. // =======================================================================
  1138.  
  1139. void object3d::translate(WORD dX, WORD dY, WORD dZ)
  1140. {
  1141.      register vertex *pt3d;
  1142.     
  1143.     points.GoToFirstNode();
  1144.     while (pt3d = (vertex*) points.GetNextNode())
  1145.         pt3d->translate(dX, dY, dZ);
  1146. }
  1147.  
  1148. // =======================================================================
  1149. //    radix sort, peforms linear-time sorting on the polygons
  1150. // =======================================================================
  1151.  
  1152. void object3d::sortPlanes()
  1153. {
  1154.     register polygon    *poly;
  1155.     register UBYTE        index;
  1156.     register WORD        count;
  1157.     
  1158.     //    Consider only the least significant radix
  1159.     polys.GoToFirstNode();
  1160.     while (poly = (polygon*) polys.GetNextNode())
  1161.     {
  1162.         index = (poly->calcAvgZ()) & 0x00FF;
  1163.         stack1[index].push(poly);
  1164.      }
  1165.     
  1166.        //    Move shtuff from stack1 to stack2, considering second least
  1167.     //    significant radix
  1168.     for (count = 255; count >= 0; count--)
  1169.     {
  1170.         while (!stack1[count].empty())
  1171.         {
  1172.             poly = (polygon*)stack1[count].pop();
  1173.             index = (poly->averageZ & 0xFF00) >> 8;
  1174.               stack2[index].push(poly);
  1175.         }
  1176.     }
  1177.     //    Rebuild the list
  1178.     polys.ForgetNodes();
  1179.     for (count = 0; count <= 255; count++)
  1180.     {
  1181.         while (!stack2[count].empty())
  1182.         {
  1183.               polys.AppendNode(stack2[count].pop());
  1184.         }
  1185.     }
  1186. }
  1187.  
  1188. // =======================================================================
  1189. //    have this object set up its normal vectors needed for gouraud shading
  1190. // =======================================================================
  1191.  
  1192. void object3d::setGNormals()
  1193. {
  1194.     register polygon *poly;
  1195.     
  1196.      polys.GoToFirstNode();
  1197.     while (poly = (polygon*) polys.GetNextNode())
  1198.         poly->setGNormals();
  1199.  
  1200.      vertex *pt3d;
  1201.     
  1202.      points.GoToFirstNode();
  1203.     while (pt3d = (vertex*) points.GetNextNode())
  1204.     {
  1205.         pt3d->avgNormal();
  1206.     }
  1207. }
  1208.  
  1209. void object3d::zeroGNormals()
  1210. {
  1211.      register vertex *pt3d;
  1212.     
  1213.      points.GoToFirstNode();
  1214.     while (pt3d = (vertex*) points.GetNextNode())
  1215.     {
  1216.         pt3d->zeroNormal();
  1217.     }    
  1218. }
  1219.  
  1220. // =======================================================================
  1221. //    universal display function that utilizes each polygon's shading
  1222. //    and facing data.  This allows you to combine gouraud, flat, and
  1223. //    nonshaded polygons in the same object.
  1224. // =======================================================================
  1225.  
  1226. void object3d::display()
  1227. {
  1228.     sortPlanes();
  1229.     register polygon *poly;
  1230.     
  1231.      polys.GoToFirstNode();
  1232.     while (poly = (polygon*) polys.GetNextNode())
  1233.         poly->renderPoly(sGouraud);
  1234.  
  1235. }
  1236.  
  1237. object3d::~object3d()
  1238. {
  1239. }
  1240.  
  1241.  
  1242. // =======================================================================
  1243. //    • world3d class definitons •
  1244. // =======================================================================
  1245.  
  1246. world3d::world3d()
  1247. {
  1248.       initSinCos();
  1249.       //initPerspect();
  1250. }
  1251.  
  1252. world3d::~world3d()
  1253. {
  1254.     //delPerspect();
  1255. }
  1256.  
  1257. void world3d::insertObject(object3d *object)
  1258. {
  1259.     objects.AppendNode(object);
  1260. }
  1261.  
  1262. void world3d::deleteObject(object3d *object, BOOL doDisposeIt)
  1263. {
  1264.     objects.RemoveNode(object, doDisposeIt);
  1265. }
  1266.  
  1267. void world3d::globalRotate(WORD tX, WORD tY, WORD tZ)
  1268. {
  1269. }
  1270.  
  1271. void world3d::draw()
  1272. {
  1273.     register object3d *object;
  1274.      
  1275.      objects.GoToFirstNode();
  1276.     while (object = (object3d*) objects.GetNextNode())
  1277.         object->display();
  1278. }
  1279.  
  1280. viewPoint::viewPoint()
  1281. {
  1282.     location.x  = 0;
  1283.     location.y  = 0;
  1284.     location.z  = 0;
  1285.     
  1286.     light.x        = 0;
  1287.     light.y        = 0;
  1288.     light.z        = 32767;
  1289.     
  1290.     view.x        = 0;
  1291.     view.y        = 0;
  1292.     view.z        = 2300;
  1293. }
  1294.  
  1295. viewPoint::~viewPoint()
  1296. {
  1297. }
  1298.